feat(web): React UI v2.0 — Phases 0-6 (backend + scaffold + shell + canvas + monitors + modals)#34
Merged
Merged
Conversation
- web/vitest.config.ts: add tests/e2e/** to exclude list so vitest no longer tries to evaluate the Playwright spec (was failing with "two different versions of @playwright/test" error). - web/tests/e2e/new-session.live.spec.ts: default E2E_BASE_URL to http://localhost:5173 (was a remote deploy URL) so the loop and CI can run against locally-served stack. Verified: npm run test:unit → 39 files, 156 passed.
- web/src/modals/ApproveRationaleModal.tsx: Modal with rationale
textarea + optional templates row + error envelope; POSTs to
/api/v1/sessions/{sid}/approvals/{tool_call_id} with
{ decision: 'approve', approver, rationale }.
- web/src/canvas/SessionCanvas.tsx: derives hitlContext from
state.toolCalls (finds first pending_approval); wires plain
onApprove (direct POST, rationale=null), onApproveWithRationale
(opens modal). Reject + Stop still no-ops, picked up by Task 53.
- web/tests/component/ApproveRationaleModal.test.tsx: 6 tests
covering disabled state, submit, template chips, error envelope.
Verified: typecheck clean; vitest 40 files / 162 tests pass; build 308 kB / 94 kB gzip.
- web/src/modals/ConfirmModal.tsx: generic confirm dialog with
{ title, body, confirmLabel, destructive, onConfirm }. Destructive
variant flips primary button to --danger and stamps a
data-destructive='true' attribute for test selection.
- web/src/components/Modal.tsx: PrimaryAction.destructive flag.
- web/src/canvas/SessionCanvas.tsx: wire HITLBand onReject -> reject
ConfirmModal (POST decision=reject); CanvasHead onStop -> stop
ConfirmModal (DELETE /sessions/{sid}).
- web/tests/component/ConfirmModal.test.tsx: 6 tests covering open,
destructive eyebrow + data-destructive attr, confirm, async error,
custom eyebrow.
Verified: typecheck clean; vitest 41 files / 168 tests pass.
- web/tests/e2e/hitl-approve.live.spec.ts: creates a session via API, polls for status=awaiting_input (60s timeout), opens the SPA on the paused session, clicks Approve in HITLBand, asserts the band hides and the backend status moves past awaiting_input. Soft-skips when the backend never reaches awaiting_input (config-dependent gating). - web/tests/e2e/retry-after-error.live.spec.ts: end-to-end Stop + retry flow — creates a session via the New Session modal (so the canvas auto-selects it), clicks Stop, confirms the destructive ConfirmModal, asserts the session reaches a terminal state, then re-creates with the same query and verifies a fresh sid. Local verification against uvicorn:8000: new-session.live: PASS hitl-approve.live: SKIPPED (no HITL pause in smoke config) retry-after-error.live: PASS
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Summary
Consolidation PR. Ships the React UI v2.0 stack from
web/end-to-end:/api/v1/*router move, 5 sidecar endpoints, env-driven CORS, StaticFiles + SPA fallback.Bundled with
chore(sonar): Tier 1 cleanup(was unmerged on a stale branch).Verification (locally)
npm run lint— 0 errors, 2 acceptable react-refresh warningsnpm run typecheck— cleannpm run test:unit— 41 files / 168 tests passnpm run build— 308 kB raw / 94 kB gzipnew-session.live.spec.ts— PASSretry-after-error.live.spec.ts— PASShitl-approve.live.spec.ts— SKIP (no HITL pause in smoke config; spec is wired but config-dependent)Stacked PRs
This is the base of a 4-PR stack:
feat/web-v2-phase-7→ responsive (Tasks 57-61)feat/web-v2-phase-8→ build/deploy/CI (Tasks 62-69)feat/web-v2-phase-9→ Streamlit retirement + parity (Tasks 70-71)After this PR squash-merges, PRs 2-4 will be re-targeted to
mainand rebased.Test plan
Web CIworkflow (added in PR 3) — once Phase 8 lands, this PR retroactively passes via squash-then-testcd web && npm run build && cd .. && uv run uvicorn runtime.api:get_app --factory --port 8000→ open http://localhost:8000/🤖 Generated with Claude Code